//
//  SocketRocketUtility.m
//  SUN
//
//  Created by 孙俊 on 17/2/16.
//  Copyright © 2017年 SUN. All rights reserved.
//

#import "SocketRocketUtility.h"
#import "ChatFace.h"
#import "ChatFaceHeleper.h"
#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}


@interface SocketRocketUtility()<SRWebSocketDelegate>
{
    int _index;
    NSTimer * heartBeat;
    NSTimeInterval reConnectTime;
}

@property (nonatomic,strong) SRWebSocket *socket;

@property (nonatomic,copy) NSString *urlString;

@end

@implementation SocketRocketUtility

+(SocketRocketUtility *)instance{
    static SocketRocketUtility *Instance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        Instance = [[SocketRocketUtility alloc] init];
    });
    return Instance;
}

#pragma mark - **************** public methods
-(void)SRWebSocketOpenWithURLString:(NSString *)urlString {
    //如果是同一个url return
    if (self.socket) {
        return;
    }
    if (!urlString) {
        return;
    }
    self.urlString = urlString;
    self.socket = [[SRWebSocket alloc] initWithURLRequest:
                   [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
    
    NSLog(@"请求的websocket地址：%@",self.socket.url.absoluteString);

    self.socket.delegate = self;
    
    [self.socket open];     //开始连接
}

-(void)SRWebSocketClose{
    if (self.socket){
        [self.socket close];
        self.socket = nil;
        //断开连接时销毁心跳
        [self destoryHeartBeat];
    }
}

- (void)sendData:(id)data {
//    NSLog(@"socketSendData --------------- %@",data);
    
    WS(weakSelf);
    dispatch_queue_t queue =  dispatch_queue_create("zy", NULL);
    dispatch_async(queue, ^{
        if (weakSelf.socket != nil) {
            // 只有 SR_OPEN 开启状态才能调 send 方法啊，不然要崩
            if (weakSelf.socket.readyState == SR_OPEN) {
                [weakSelf.socket send:data];    // 发送数据
            } else if (weakSelf.socket.readyState == SR_CONNECTING) {
                NSLog(@"正在连接中，重连后其他方法会去自动同步数据");
                [self reConnect];
            } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
                // websocket 断开了，调用 reConnect 方法重连
                NSLog(@"重连");
                [self reConnect];
            }
        } else {
            NSLog(@"没网络，发送失败，一旦断网 socket 会被我设置 nil 的");
        }
    });
}

#pragma mark - **************** private mothodes
//重连机制
- (void)reConnect
{
    [self SRWebSocketClose];

    //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
    if (reConnectTime > 2) {
        //您的网络状况不是很好，请检查网络后重试
        if (self.connectChange) {
            self.connectChange(1);
        }
        return;
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.socket = nil;
        [self SRWebSocketOpenWithURLString:self.urlString];
        NSLog(@"重连");
    });
    
    //重连时间2的指数级增长
    reConnectTime+=1;
}


//取消心跳
- (void)destoryHeartBeat
{
    dispatch_main_async_safe(^{
        if (heartBeat) {
            if ([heartBeat respondsToSelector:@selector(isValid)]){
                if ([heartBeat isValid]){
                    [heartBeat invalidate];
                    heartBeat = nil;
                }
            }
        }
    })
}

//初始化心跳
- (void)initHeartBeat
{
    dispatch_main_async_safe(^{
        [self destoryHeartBeat];
        //心跳设置为3分钟，NAT超时一般为5分钟
        heartBeat = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
        //和服务端约定好发送什么作为心跳标识，尽可能的减小心跳包大小
        [[NSRunLoop currentRunLoop] addTimer:heartBeat forMode:NSRunLoopCommonModes];
    })
}

-(void)sentheart{
    //发送心跳 和后台可以约定发送什么内容  一般可以调用ping  我这里根据后台的要求 发送了data给他
    NSDictionary *dict=@{@"MsgType":@3,@"MsgTypeChild":@31};
    NSString *str=[TGTools convertToJSONData:dict];
    [self sendData:str];
}

////pingPong
//- (void)ping{
//    if (self.socket.readyState == SR_OPEN) {
//        [self.socket sendPing:nil];
//    }
//}


- (void)senMessage:(ZXMessageModel *)model{
    if (model.messageType==ZXMessageTypeText) {
        NSString *strText=[self sendMessageConversion:model.text];
        NSDictionary *dict=@{@"MsgType":@2,@"MsgTypeChild":@21,@"Content":strText,@"Guid":model.Guid,@"UserName":[UserModel userModel].NickName};
        NSString *str=[TGTools convertToJSONData:dict];
        str=[str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        [self sendData:str];
    }else if (model.messageType==ZXMessageTypeImage){
//        WS(weakSelf);
//        [[ChatVM manage] postImageWithImage:model.image andSuccess:^(id returnValue) {
//            NSDictionary *dict=@{@"MsgType":@2,@"MsgTypeChild":@22,@"Content":returnValue,@"Guid":model.Guid,@"UserName":[UserModel userModel].NickName};
//            NSString *str=[TGTools convertToJSONData:dict];
//            str=[str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
//            [weakSelf sendData:str];
//        } andFail:^(NSString *errorMessage, NSError *error) {
//            
//        }];
    }else if (model.messageType==ZXMessageTypeBlack){
        NSDictionary *dict=@{@"MsgType":@1,@"MsgTypeChild":@12,@"BlackPeople":model.from.UserId};
        NSString *str=[TGTools convertToJSONData:dict];
        str=[str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        [self sendData:str];
    }else if (model.messageType==ZXMessageTypeDelete){
        NSDictionary *dict=@{@"MsgType":@1,@"MsgTypeChild":@11,@"Guid":model.Guid};
        NSString *str=[TGTools convertToJSONData:dict];
        str=[str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        [self sendData:str];
    }else if (model.messageType==ZXMessageTypeDeleteAll){
        NSDictionary *dict=@{@"MsgType":@1,@"MsgTypeChild":@13,@"BlackPeople":model.from.UserId};
        NSString *str=[TGTools convertToJSONData:dict];
        str=[str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        [self sendData:str];
    }
}

- (NSString *)sendMessageConversion:(NSString *)text{
    if (text.length==0) {
        return nil;
    }
    NSString *regex_emoji = @"\\[[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\]"; //
    NSError *error = nil;
    NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error];
    NSArray *resultArray = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)];
    
    if (resultArray.count>0) {
        NSTextCheckingResult *match=resultArray[0];
        NSRange range = [match range];
        //获取原字符串中对应的值
        NSString *subStr = [text substringWithRange:range];
        ChatFaceGroup   *group = [[[ChatFaceHeleper  sharedFaceHelper] faceGroupArray] objectAtIndex:0];
        for (ChatFace *face in group.facesArray) {
            if ([face.faceName isEqualToString:subStr]) {
                text=[text stringByReplacingOccurrencesOfString:subStr withString:[NSString stringWithFormat:@"#%@#",face.faceID]];
                if (resultArray.count>1) {
                    text=[self sendMessageConversion:text];
                }
                break;
            }
        }
    }
    return text;
}

- (NSString *)getMessageConversion:(NSString *)text{
    NSString *regex_emoji = @"\\#[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\#"; //
    NSError *error = nil;
    NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error];
    NSArray *resultArray = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)];
    
    if (resultArray.count>0) {
        NSTextCheckingResult *match=resultArray[0];
        NSRange range = [match range];
        //获取原字符串中对应的值
        NSString *subStr = [text substringWithRange:range];
        ChatFaceGroup   *group = [[[ChatFaceHeleper  sharedFaceHelper] faceGroupArray] objectAtIndex:0];
        NSString *subFace=[subStr stringByReplacingOccurrencesOfString:@"#" withString:@""];
        for (ChatFace *face in group.facesArray) {
            if ([face.faceID isEqualToString:subFace]) {
                text=[text stringByReplacingOccurrencesOfString:subStr withString:[NSString stringWithFormat:@"%@ ",face.faceName]];
                if (resultArray.count>1) {
                    text=[self getMessageConversion:text];
                }
                break;
            }
        }
    }
    return text;
}

#pragma mark - socket delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    //每次正常连接的时候清零重连时间
    reConnectTime = 0;
    //开启心跳
    [self initHeartBeat];
    if (webSocket == self.socket) {
        NSLog(@"************************** socket 连接成功************************** ");
        if (self.connectChange) {
            self.connectChange(0);
        }
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket 连接失败************************** ");
        _socket = nil;
        //连接失败就重连
        [self reConnect];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    if (webSocket == self.socket) {
        NSLog(@"************************** socket连接断开************************** ");
        NSLog(@"被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
        [self SRWebSocketClose];
        if (self.connectChange) {
            self.connectChange(1);
        }
    }
}

/*该函数是接收服务器发送的pong消息，其中最后一个是接受pong消息的，
 在这里就要提一下心跳包，一般情况下建立长连接都会建立一个心跳包，
 用于每隔一段时间通知一次服务端，客户端还是在线，这个心跳包其实就是一个ping消息，
 我的理解就是建立一个定时器，每隔十秒或者十五秒向服务端发送一个ping消息，这个消息可是是空的
 */
-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
    NSLog(@"reply===%@",reply);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket收到数据了************************** ");
        NSLog(@"message:%@",message);
        ScoketLotteryModel *model=[ScoketLotteryModel mj_objectWithKeyValues:[TGTools JsonToDict:message]];
        if (self.acceptBlock) {
            self.acceptBlock(model);
        }
//        NSString *strMessage=[self getMessageConversion:message];
//        ZXMessageModel *messageModel=[ZXMessageModel modelWithMessageDict:[TGTools JsonToDict:strMessage]];
//        if (self.acceptBlock) {
//            self.acceptBlock(messageModel);
//        }
    }
}

#pragma mark - **************** setter getter
- (SRReadyState)socketReadyState{
    return self.socket.readyState;
}

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


@end
